package com.auth.client.config.interceptor;

import com.auth.client.config.auth.Auth;
import com.auth.client.config.context.AppContext;
import com.auth.client.config.context.UserContext;
import com.auth.client.config.domain.User;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.web.servlet.error.BasicErrorController;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import org.springframework.web.util.WebUtils;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Arrays;
import java.util.Date;

/**
 * 拦截
 *
 * @author: mhSui 2020/07/01
 */
public class AuthInterceptor extends HandlerInterceptorAdapter {

    private static final Logger log = LoggerFactory.getLogger(AuthInterceptor.class);

    public AuthInterceptor(){}

    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
        //判断是否能编译HandlerMethod，instanceof双目运算符
        if (!(handler instanceof HandlerMethod)){
            return true;
            //Web控制器方法所在的Web控制器bean的类型
        }else if (((HandlerMethod)handler).getBeanType() == BasicErrorController.class){
            return true;
        }else {
            HandlerMethod hm = (HandlerMethod)handler;
            //查找对应权限
            Auth auth = (Auth)hm.getMethodAnnotation(Auth.class);
            if (null == auth){
                auth = (Auth)hm.getBeanType().getAnnotation(Auth.class);
            }

            if (null != auth && !auth.mustAuthentication()){
                return true;
            }else {
                String token = request.getHeader("x-token");
                if (null == token){
                    Cookie cookie = WebUtils.getCookie(request,"x-token");
                    if (null != cookie){
                        token = cookie.getValue();
                    }
                }

                if (StringUtils.isEmpty(token)){
                    this.unauthorized(response);
                    return false;
                }else {
                    User user = null;
                    JWTVerifier verifier = JWT.require(AppContext.get().getAlgorithm()).withIssuer("u").build();

                    try {
                        DecodedJWT jwt = verifier.verify(token);
                        Date expiresAt = jwt.getExpiresAt();
                        if (null != expiresAt && (new Date()).before(expiresAt)) {
                            String userId = jwt.getSubject();
                            user = new User(userId);
                            user.setToken(token);
                            Claim mobile = jwt.getClaim("mobile");
                            if (null != mobile) {
                                user.setMobile(mobile.asString());
                            }
                        }
                    }catch (JWTVerificationException e){
                        log.error(e.getMessage(),e);
                    }

                    if (null == user) {
                        this.unauthorized(response);
                        return false;
                    }else if (null != auth && !auth.onlyAuthentication()){
                        String action = auth.value();
                        if (StringUtils.isEmpty(action) && (CollectionUtils.isEmpty(Arrays.asList(user.getActions())) || !Arrays.asList(user.getActions()).contains(action))) {
                            this.forbidden(response);
                            return false;
                        } else {
                            UserContext.set(user);
                            return true;
                        }
                    }else {
                        UserContext.set(user);
                        return true;
                    }
                }
            }


        }
    }


    private void unauthorized(HttpServletResponse response) throws IOException {
        response.sendError(401);
        response.getWriter().write("{\"success\":false,\"code\":401,\"message\":\"没有登录.\"}");
        response.getWriter().close();
    }

    private void forbidden(HttpServletResponse response) throws IOException {
        response.sendError(403);
        response.getWriter().write("{\"success\":false,\"code\":403,\"message\":\"没有权限.\"}");
        response.getWriter().close();
    }

    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserContext.clear();
    }
}
